#pragma once
#include <iostream>
#include <sys/epoll.h>
#include "Socket.hpp"
#include <memory>
class EpollServer
{
    static const int size = 64;
    static const int defaultfd = -1;

public:
    EpollServer(uint16_t port) : _epoll(std::make_unique<TcpSocket>()), _isruning(false)
    {
        _epoll->BuildTcpSocketServer(port); // 构建服务器

        _epfd = epoll_create(128); // 创建epoll。。。创建底层红黑树存需要关心的fd，就绪队列已经就绪的fd
        if (_epfd < 0)
        {
            LOG(LogLevel::FATAL) << "create epfd error";
            exit(CREATE_EPFD_ERR);
        }
        // 创建成功
        // 将listenfd添加进内核
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = _epoll->Fd();
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, _epoll->Fd(), &ev);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "epoll_ctl error";
            exit(EPOLL_CTL_ERR);
        }
        LOG(LogLevel::DEBUG) << "ctl success listenfd";
    }
    void Start()
    {
        _isruning = true;
        int timeout = -1;
        while (_isruning)
        {
            int n = epoll_wait(_epfd, _revs, size, -1);
            switch (n)
            {
            case 0:
                LOG(LogLevel::DEBUG) << "timewait out...";
                break;
            case -1:
                LOG(LogLevel::ERROR) << "wait error";
                break;
            default:
                Assignment(n);
                break;
            }
        }
    }
    // 将已就绪的分发到对应的处理区
    void Assignment(int n)
    {
        LOG(LogLevel::DEBUG) << "event ready ...";
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t revent = _revs[i].events;
            if (sockfd == _epoll->Fd())
            {
                // 建立连接
                Accept();
            }
            else
            {
                // 进行读/写
                Recv(_revs[i]);
            }
        }
    }
    // 建立连接
    void Accept()
    {
        InetAddr client;
        int sockfd = _epoll->Accept(&client);
        if (sockfd < 0)
        {
            LOG(LogLevel::ERROR) << "accept error";
            return;
        }
        // 成功
        // 将新建立连接的fd添加到内核
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = sockfd;
        epoll_ctl(_epfd, EPOLL_CTL_ADD, sockfd, &ev);
    }
    // 进行读
    void Recv(epoll_event &ev)
    {
        char buffer[1024];
        int sockfd = ev.data.fd;
        ssize_t size = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (size > 0)
        {
            buffer[size] = 0;
            std::cout << "client say@ " << buffer << std::endl;
        }
        else if (size == 0)
        {
            LOG(LogLevel::DEBUG) << "client quit";
            close(sockfd);
            epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
        }
        else
        {
            LOG(LogLevel::FATAL) << "recv 异常";
            close(sockfd);
            epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
        }
    }
    ~EpollServer()
    {
        if (_epfd > 0)
            close(_epfd);
    }

private:
    std::unique_ptr<Socket> _epoll;
    bool _isruning;
    int _epfd;
    struct epoll_event _revs[size];
};